defmodule EliPhxPlay.ChatSchema.Groups do
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:group_id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id

  schema "groups" do
    field :group_name, :string
    field :group_description, :string
    field :group_avatar, :string
    field :group_code, :string


    belongs_to :owner, EliPhxPlay.ChatSchema.Users,
      foreign_key: :owner_id,
      references: :user_id,
      type: :binary_id

    has_many :group_members, EliPhxPlay.ChatSchema.GroupMembers,
      foreign_key: :group_id,
      references: :group_id

    timestamps()
  end

  @doc """
  创建群聊时使用的 changeset
  支持头像文件上传
  """
def changeset(group, attrs) do
  group
  |> cast(attrs, [:group_name, :group_description, :group_avatar, :owner_id, :group_code])
  |> validate_required([:group_name, :owner_id])
  |> validate_group_name()
  |> validate_group_description()
  |> validate_avatar_path()
  |> validate_owner_id_present()
  |> unique_constraint(:group_code, message: "群号生成冲突，请重试")
end


  @doc """
  更新群聊信息时使用的 changeset
  """
  def update_changeset(group, attrs) do
    group
    |> cast(attrs, [:group_name, :group_description, :group_avatar, :group_code])
    |> validate_group_name()
    |> validate_group_description()
    |> validate_avatar_path()
    |> validate_required([:group_name, :owner_id])
    |> unique_constraint(:group_code, message: "群号已被使用")
  end


  @doc """
  转让群主时使用的 changeset
  """
  def transfer_ownership_changeset(group, attrs) do
    group
    |> cast(attrs, [:owner_id])
    |> validate_required([:owner_id])
  end

  # === 私有验证函数 ===

  defp validate_owner_id_present(changeset) do
    case get_change(changeset, :owner_id) do
      nil ->
        add_error(changeset, :owner_id, "新群主ID不能为空")
      owner_id when is_binary(owner_id) and byte_size(owner_id) > 0 ->
        changeset
      _ ->
        add_error(changeset, :owner_id, "新群主ID格式不正确")
    end
  end

  defp validate_group_name(changeset) do
    changeset
    |> validate_length(:group_name, min: 1, max: 50,
        message: "群名长度必须在1-50字符之间")
    |> validate_format(:group_name, ~r/^[^\s].*[^\s]$|^[^\s]$/,
        message: "群名不能以空格开头或结尾")
  end

  defp validate_group_description(changeset) do
    case get_change(changeset, :group_description) do
      nil -> changeset
      "" -> changeset
      description ->
        if String.length(description) <= 500 do
          changeset
        else
          add_error(changeset, :group_description, "群描述不能超过500字符")
        end
    end
  end

  # 修改：验证头像文件路径而不是URL
  defp validate_avatar_path(changeset) do
    case get_change(changeset, :group_avatar) do
      nil -> changeset  # 没有修改
      "" -> changeset   # 空字符串，允许（使用默认头像）
      path ->
        if valid_avatar_path?(path) do
          changeset
        else
          add_error(changeset, :group_avatar, "头像文件路径格式不正确")
        end
    end
  end

  # 新增：验证头像文件路径格式
  defp valid_avatar_path?(path) when is_binary(path) do
    # 检查是否为相对路径，且以允许的图片格式结尾
    allowed_extensions = [".jpg", ".jpeg", ".png", ".gif", ".webp"]

    # 确保路径不以 / 开头（相对路径）
    # 确保路径包含允许的图片扩展名
    # 确保路径不包含危险字符
    not String.starts_with?(path, "/") and
    Enum.any?(allowed_extensions, &String.ends_with?(String.downcase(path), &1)) and
    not String.contains?(path, "..") and  # 防止目录遍历攻击
    String.match?(path, ~r/^[a-zA-Z0-9\/_\-\.]+$/)  # 只允许安全字符
  end

  defp valid_avatar_path?(_), do: false

  # === 公共辅助函数 ===

  @doc """
  获取群头像的完整访问URL
  如果没有设置头像则返回默认头像
  """
  def avatar_url(%__MODULE__{group_avatar: nil}), do: "/images/default-group-avatar.png"
  def avatar_url(%__MODULE__{group_avatar: ""}), do: "/images/default-group-avatar.png"
  def avatar_url(%__MODULE__{group_avatar: path}) do
    # 将相对路径转换为完整的访问URL
    "/uploads/group_avatars/#{path}"
  end

  @doc """
  获取群头像的本地文件系统路径
  用于服务器端文件操作
  """
  def avatar_file_path(%__MODULE__{group_avatar: nil}), do: nil
  def avatar_file_path(%__MODULE__{group_avatar: ""}), do: nil
  def avatar_file_path(%__MODULE__{group_avatar: path}) do
    # 返回完整的文件系统路径
    Path.join([Application.get_env(:eli_phx_play, :uploads_path, "priv/static/uploads"), "group_avatars", path])
  end

  @doc """
  生成唯一的头像文件名
  格式：群组ID_时间戳.扩展名
  """
  def generate_avatar_filename(group_id, original_filename) do
    extension = Path.extname(original_filename)
    timestamp = DateTime.utc_now() |> DateTime.to_unix()
    "#{group_id}_#{timestamp}#{extension}"
  end
end
